import { useUserStore } from "@store/useUserStore"
import { useMenuStore } from  "@store/useMenuStore"
import config from "@config"
import { ElMessage } from "element-plus"
import AppRouter from "./index"
import { useRouter } from "vue-router"
let router:any = null
// 进度条
import Nprogress from 'nprogress'
import 'nprogress/nprogress.css'

// 全局前置导航守卫
export const beforeEach = async (to)=>{
    Nprogress.start()
    router = useRouter()
    // 判断是否已经在登录页面
    if(to.path == '/login'){
        return true
    }
    // 如果没有token，那么就跳转到登录页
    if(!localStorage.getItem('TOKEN')){
        return '/login'
    }
    // 进入后台管理系统首页  hooks => userLogin.ts：router.push('/')
    try {
        const userStore = useUserStore()
        // 这句代码可以代替持久化存储
        await userStore.initUserInfo();
        const menuStore = useMenuStore()
        // 动态路由的方法，在这里调用
        initRouter(menuStore.menuList)

        /**
         * to.fullpath是完整路径，包括参数
         * to.matched目标路由匹配的组件,是一个数组
         * 
         * 刷新页面不会出现空白页,并且保持当前路由
         *  
         *  如果点击菜单按钮跳转，先加载了layout，此时matched有两个，一个是'/'，一个是'/system/role'
         *  刷新页面时，没有加载layout，matched是空数组，因为动态路由是layout的子路由
         *      router.push(to.fullPath) 写上这个后，就可以正常显示页面了
         */
        if( to.matched.length == 0 ){
            router.push( to.fullPath );
        }

        // 如果用户是最高权限("*:*:*")，直接通行
        if(userStore.permissions == config.PERMISSIONS){
            return true
        }
        // 如果没一个路由，不能进入某页面
        if(!menuStore.menuMap.has(to.path)){
            ElMessage.error('sorry~~您访问的页面不存在')
            AppRouter.replace('/')
            return false
        }
        return true
        
    } catch (e) {
        // console.log(e);
        // 如果没有做持久化存储，store中的数据为空，会走catch，这里让它跳转到登录页
        //next('/login')
        //return '/login'
        
    }
    
    return true

    
}
// 动态路由
const initRouter = (menuList:any[])=>{
    // 把原始数组复制一份
    const newMenus = menuList || [];
    let menu = [...newMenus]
    // console.log('原始数据',menu);
    
    // 调用一次重构的方法：把数据中的component:字符串的形式，换成了懒加载路由可以对应组件的形式
    let menuRouter:any = filterAsyncRouter(menu)
    // console.log('一次重构',menuRouter);
    // 调用二次重构的方法：
    //  1.把所有的二级路由变成了一级
    //  2.往route中，添加对应关系的一级(包括children)和二级
    menuRouter = flatAsyncRoutes( menuRouter )
    // console.log('二次重构',menuRouter);

    // 添加路由
    menuRouter.forEach(item=>{
        // console.log(router);
        if(item.path!=="http://www.xuexiluxian.cn"){
            // 添加一个新的路由记录，将其作为一个已有路由的子路由。
            // addRoute第一个参数是父路由的name
            router.addRoute('layout',item)
        }
    })  
}
// 路由菜单数据的重构
const filterAsyncRouter = (routerMap:any[])=>{ //routerMap里的数据是将原始数据复制之后得到的
    
    const accessdRouters:object[] = []
    routerMap.forEach(item=>{
        let route = {
            path:item.path,//字符串
            name:item.name,//字符串
            meta:item.meta,//Proxy(Object)
            children:item.children?filterAsyncRouter(item.children) : null,//Array
            component: loadComponent(item.component) //()=>import("src/views/system/role/index.vue")
            //item.component
                //system/role/index
            //item.path
                //system/role
            
        }
        accessdRouters.push(route)
    })
    return accessdRouters
}

//检索全局文件
const modulesPath = import.meta.glob('@renderer/views/**/*.vue') 


const modulesMap = {}//用于简化文件路径
//Object.keys返回一个由对象的键组成的数组
Object.keys(modulesPath).forEach(key=>{
    //key是每个文件的路径，把它们重构成和routerMap的item.component一样的结构
    const componentName = key.replace('/src/views/','').replace('.vue','')

    // if( key.includes('index') ){
    //     modulesMap[`${componentName}/index`] = modules[key];
    // }

    // 将重构之后的路径当做modulesMap对象的属性
    modulesMap[componentName] = modulesPath[key]
    // console.log(modulesMap); 
        //login/Login: ()=>import("src/views/login/Login.vue")
        //login/module/User: ()=>import("src/views/login/User.vue")
        //system/role/index:()=>import("src/views/system/role/index.vue")
        
}) 
// console.log('简化文件路径',modulesMap); 

// 一次重构，包装动态路由组件路径
const loadComponent = (component)=>{
    //如果后端返回的item.children[i].component(字符串)存在
    if (component) {
        // 首先尝试匹配传入的 component
        if (modulesMap.hasOwnProperty(component)) {
            return modulesMap[component];
        }
        // 如果没有匹配到，尝试在 component 后加上 '/index' 进行匹配
        const componentWithIndex = `${component}/index`;
        if (modulesMap.hasOwnProperty(componentWithIndex)) {
            return modulesMap[componentWithIndex];
        }
    }
    
}

// 二次重构，全部变成一级路由。因为一级只是做个分类，点二级才会跳转路径
function flatAsyncRoutes( routes, breadcrumb:any=[] ){
    // breadcrumb是一次重构的结果，里面是每一项是一级路由，children是二级路由
    let res:any = []
    routes.forEach(route=>{
        // route是每一个路由对象

        // 将当前路由对象复制到tmp对象里
        // 当前路由对象
        const tmp = {...route}
        
        if (tmp.children) {
          //递归之前，breadcrumb刚开始是空数组，随后网里面添加了当前路由对象
          //递归之后，breadcrumb是[{route}}，把它拆开放到childrenBreadcrumb数组里
          let childrenBreadcrumb = [...breadcrumb];
          //将每一个路由对象放进一个数组里
          //递归之后，将tmp.children里的二级路由对象放到外层变成一级  
          childrenBreadcrumb.push(route);
          //递归之后，此时childrenBreadcrumb里面包含当前原路由对象和已经变成一级的原二级路由对象

          //和tmp一样，是当前一级路由对象
          //递归之后，将tmp.children里的二级路由对象复制到tmpRoute对象里  
          let tmpRoute = { ...route };
          //往tmpRoute.meta身上放一个breadcrumb属性，值是当前原路由对象，包括children
          //递归之后，breadcrumb的属性值是tmp.children里的二级路由对象  
          //递归之后，childrenBreadcrumb[0]是原路由对象，childrenBreadcrumb[1,...]是已经变成一级的原二级路由对象
          tmpRoute.meta.breadcrumb = childrenBreadcrumb;
          //递归之前，删除二级
          //递归之后，删除三级
          delete tmpRoute.children;
          //递归前：将一级路由对象放进新数组里
          //递归后：将一级路由对象&已经变成一级的原二级路由对象放进新数组里
          res.push(tmpRoute);

          let childrenRoutes = flatAsyncRoutes(tmp.children, childrenBreadcrumb);
          childrenRoutes.map(item => {
              res.push(item)
          })

          
          
        }else{
            /**
             * 二级没有children，一级也可能没children
             *  如果一级没有children，直接push，breadcrumb为空数组
             *      然后将 [当前路由对象] 放进route.meta里
             *  如果二级没有children  tmp里面存的是二级，breadcrumb里存的是[route]
             *      然后将 [route,当前路由对象] 放进route.meta里
             *  
             */
            let tmpBreadcrumb = [...breadcrumb];
            tmpBreadcrumb.push(tmp)
            tmp.meta.breadcrumb = tmpBreadcrumb;
            // delete tmp.children;
            res.push(tmp);

        }
    })

    return res
}












// 全局后置导航守卫
export const afterEach = ()=>{
    Nprogress.done()
}

